package output;

import lupos.LexUnitAnnotation;
import lupos.Lexeme;
import lupos.AnnotationSet;
import java.io.IOException;
import java.util.List;
import java.util.ArrayList;
import java.util.Set;
import java.util.TreeSet;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import ontology.Ontology;


/** This class implements a harvested lexical entry, and contains a 
 * toXML() method which creates XML with the following format:
 * 
 *   entry @fn-id @fn-name @pos (@incorporatedFE)
 *     > semantictype
 *     > orthography
 *         > word*
 *     > examples
 *         > example*
 *     > framesets
 *         > frameset*
 * 
 * The constructor method takes a LexUnitAnnotation object and 
 * converts it into a lexical entry, in consultation with the 
 * FrameNet ontology (implemented as an Ontology object). 
 */

public class LexEntry {
	
	public String fnId;
	public String fnName;	
	public String pos;
	public SemanticType semanticType;
	public String incorporatedFE;	
	public String definition;
	public List<Lexeme> words = new ArrayList<Lexeme>();
	public List<Example> examples = new ArrayList<Example>();
	public List<FrameSet> framesets = new ArrayList<FrameSet>();
	
	/** The following method does pretty much all the work. */
	
	public LexEntry(LexUnitAnnotation a,Ontology o,String fnDistro) throws IOException, ParserConfigurationException, SAXException {
		fnId = a.id;
		fnName = a.name;
		pos = a.pos;
		semanticType = new SemanticType(a.frame,o);
		incorporatedFE = a.incorporatedFE;
		definition = a.definition;
		words = a.lexemes;
		for(AnnotationSet s: a.annotationSets) {
			// converts every annotated sentence into an example object 
			examples.add(new Example(s,o,semanticType));
		}
		// FIRST FRAMESET:
		// all non-Core dependents are omitted
		FrameSet fs1 = new FrameSet(1);
		// every example is converted into a subcat frame (i.e. a set):
		for (Example e: examples) {
			SubCatFrame vf = new SubCatFrame(e,fnId,fnDistro);
			fs1.frames.add(vf);
		}		
		// remove duplicate valence frames from fs1:
		List<SubCatFrame> newFrames = new ArrayList<SubCatFrame>();
		for (SubCatFrame f: fs1.frames) {
			SubCatFrame found = null;
			for (SubCatFrame g: newFrames) {
				if (f.arguments.equals(g.arguments)) { // same arguments
					found = g;
					break;
				}
			}
			if (found==null) newFrames.add(f);
			else {
				found.instances.addAll(f.instances);
			}
		}
		fs1.frames = newFrames;
		// identity frames with duplicate arguments:
		// argument identity = same FE
		for (SubCatFrame f: fs1.frames) {
			// Does it contain duplicate arguments?
			Set<String> fes = new TreeSet<String>();
			for (Argument b: f.arguments) {
				fes.add(b.semanticRole.name);
			}
			if (fes.size()<f.arguments.size()) {
				f.status = "duplicate-role";
			}
		}
		// tag subcat frames with no or more than one Ext argument:		
		for (SubCatFrame f: fs1.frames) {
			if (f.status.equals("")) {
				int noOfExts = 0;
				for (Argument b: f.arguments) {
					if (b.syntacticRole.equals("Ext")) {
						noOfExts++;
					}
				}
				if (noOfExts!=1) f.status = "EPP";
			}
		}
		framesets.add(fs1);
		// identify maybe passive frames:	
		for (SubCatFrame f: fs1.frames) {
			if (f.status.equals("")) {
				// identify if passive or not:
				// find semantic role of Ext argument:
				String roleOfExt = "";
				for (Argument b: f.arguments) {
					if (b.syntacticRole.equals("Ext")) {
						roleOfExt = b.semanticRole.name;
						break;
					}
				}
				// check other frames for an Obj with same role:
				for (SubCatFrame h: fs1.frames) {
					for (Argument b: h.arguments) {
						if (b.syntacticRole.equals("Obj") && b.semanticRole.name.equals(roleOfExt)) {
							f.status = "maybe-passive";
							break;
						}
					}
				}
			}
		}
		// identify probably passive frames:	
		for (SubCatFrame f: fs1.frames) {
			if (f.status.equals("maybe-passive")) {
				// identify if really passive or not:
				// Does EVERY annotated sentence assign the verb to VVN or VVD-VVN?
				boolean probablyPassive = true;
				for (String i: f.instances) {
					// find right example:
					for (Example e: this.examples) {
						if (e.fnAnnoId.equals(i)) {
							if (!(e.targetPos.equals("VVN") || e.targetPos.equals("VVD-VVN"))) { 
								probablyPassive = false;;
								break;
							}
						}
					}
					if (!probablyPassive) break;
				}
				if (probablyPassive) f.status = "probably-passive";
			}
		}
		// SECOND FRAMESET (end of section 4):
		FrameSet fs2 = new FrameSet(2);
		for (SubCatFrame f: fs1.frames) {
			if (f.status.equals("") || f.status.equals("maybe-passive")) {
				fs2.frames.add(f.clone());
			}
		}
		framesets.add(fs2);
		// THIRD FRAMESET (role inheritance):
		FrameSet fs3 = new FrameSet(3);
		for (SubCatFrame f: fs2.frames) {
			fs3.frames.add(f.clone2());
		}
		// remove duplicate valence frames from fs3:
		newFrames = new ArrayList<SubCatFrame>();
		for (SubCatFrame f: fs3.frames) {
			SubCatFrame found = null;
			for (SubCatFrame g: newFrames) {
				if (f.arguments.equals(g.arguments)) { // same arguments
					found = g;
					break;
				}
			}
			if (found==null) newFrames.add(f);
			else {
				found.instances.addAll(f.instances);
			}
		}
		fs3.frames = newFrames;
		framesets.add(fs3);
		// FOURTH FRAMESET (CORENESS SETS):
		FrameSet fs4 = new FrameSet(4);
		for (SubCatFrame f: fs2.frames) {
			fs4.frames.add(f.clone3());
		}
		// remove duplicate valence frames from fs4:
		newFrames = new ArrayList<SubCatFrame>();
		for (SubCatFrame f: fs4.frames) {
			SubCatFrame found = null;
			for (SubCatFrame g: newFrames) {
				if (f.arguments.equals(g.arguments)) { // same arguments
					found = g;
					break;
				}
			}
			if (found==null) newFrames.add(f);
			else {
				found.instances.addAll(f.instances);
			}
		}
		fs4.frames = newFrames;
		framesets.add(fs4);		
		
		
	}
	
	public LexEntry(Element e) {
		pos = e.getAttribute("pos");
		NodeList ns = e.getChildNodes();
		for (int i=0;i<ns.getLength();i++) {
			Node n = ns.item(i);
			if (n.getNodeName().equals("semantictype")) {
				semanticType = new SemanticType((Element) n);
			}
			else if (n.getNodeName().equals("orthography")) {
				NodeList nns = ((Element) n).getChildNodes();
				for (int j=0;j<nns.getLength();j++) {
					Node nn = nns.item(j);
					if (nn.getNodeName().equals("word")) {
						words.add(new Lexeme((Element) nn));
					}
				}
			}
		}
	}
	
	public String toXML() {
		String s = ""; //"<?xml-stylesheet href=\"http://tflex.googlecode.com/svn/trunk/xslt/stylesheet.xsl\" type=\"text/xsl\"?>\n\n";
	    s = s + "<entry fn-id=\"";
		s = s + fnId + "\" fn-name=\"";
		s = s + fnName + "\" pos=\"";		
		s = s + pos + "\"";
		if (!incorporatedFE.equals("")) {
			s = s + " incorporatedFE=\"" + incorporatedFE + "\">\n";
		}
		else {
			s = s + ">\n";
		}
		s = s + semanticType.toXML(2);
		s = s + "  <definition><![CDATA[" + definition + "]]></definition>\n";
		s = s + "  <orthography>\n";
		for (Lexeme l: words) {
			s = s + l.toXML();
		}
		s = s + "  </orthography>\n";
		s = s + "  <examples>\n";
		for (Example e: examples) {
			s = s + e.toXML();
		}
		s = s + "  </examples>\n";
		s = s + "  <framesets>\n";		
		for (FrameSet f: framesets) {
			s = s + f.toXML();
		}
		s = s + "  </framesets>\n";	
		return s + "</entry>";
	}
	
}
